﻿using System;
using System.Collections;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.ApplicationPages;
using WoltersKluwer.SPChainGang.Core.Constants;
using WoltersKluwer.SPChainGang.Core.ExtensionMethods;
using WoltersKluwer.SPChainGang.Core.TimerJobs;
using WoltersKluwer.SPChainGang.Core.Util;
using WoltersKluwer.SPChainGang.Web.UserControls;

namespace WoltersKluwer.SPChainGang.Web.ChainGangApplicationPages
{
    //TODO: Improve performance of this page: loads too slowly on staging
    public partial class SPChainGangWarden : OperationsPage //LayoutsPageBase
    {
        protected ListBox ReportsList, SPChainGangJobs;
        protected ListPicker ConfigurationListPicker;

        ChainGangJob currentJob;

        protected ChainGangJob CurrentJob
        {
            get
            {
                if (currentJob == null)
                {
                    Guid jobId = Request["JobId"].ConvertToGuid();
                    if (jobId != Guid.Empty)
                    {
                        currentJob = SPFarm.Local.GetObject(jobId) as ChainGangJob;
                    }
                }
                return currentJob;
            }
        }

        private Action CurrentAction
        {
            get
            {
                var jobId = Request["JobId"];
                if (jobId.EqualsByContent("New"))
                    return Action.AddNewJob;

                return CurrentJob == null ? Action.ManageJobs : Action.ModifyJob;
            }
        }
        
        protected string ScheduleTypeName
        {
            get
            {
                string scheduleTypeName = SetCurrentSheldueName();
                return String.IsNullOrEmpty(scheduleTypeName) ? CurrentScheduleTypeName : scheduleTypeName;
            }
        }

        private string SetCurrentSheldueName()
        {
            string scheduleTypeName = string.Empty;
            if (RadioButtonSPYearlySchedule.Checked)
            {
                scheduleTypeName = typeof(SPYearlySchedule).Name;
            }
            else if (RadioButtonSPMonthlySchedule.Checked)
            {
                scheduleTypeName = typeof(SPMonthlySchedule).Name;
            }
            else
                if (RadioButtonSPWeeklySchedule.Checked)
                {
                    scheduleTypeName = typeof(SPWeeklySchedule).Name;
                }
                else
                    if (RadioButtonSPDailySchedule.Checked)
                    {
                        scheduleTypeName = typeof(SPDailySchedule).Name;
                    }
                    else
                        if (RadioButtonSPHourlySchedule.Checked)
                        {
                            scheduleTypeName = typeof(SPHourlySchedule).Name;
                        }
                        else
                            if (RadioButtonSPMinutesSchedule.Checked)
                            {
                                scheduleTypeName = typeof(SPMinuteSchedule).Name;
                            }
                            else
                                if (RadioButtonSPOneTimeSchedule.Checked)
                                {
                                    scheduleTypeName = typeof(SPOneTimeSchedule).Name;
                                }
            return scheduleTypeName;
        }

        protected string CurrentScheduleTypeName
        {
            get { return CurrentJobSchedule != null ? CurrentJobSchedule.GetType().Name : null; }
        }

        private SPSchedule CurrentJobSchedule
        {
            get { return CurrentAction == Action.ModifyJob ? CurrentJob.Schedule : null; }
        }

        protected Guid ChosenSiteCollectionId
        {
            get
            {
                return SiteCollectionSelector.CurrentId.ConvertToGuid();
            }
        }

        public override string PageToRedirectOnCancel
        {
            //raw url to preserve site collection paths
            get { return new Uri(Request.Url, Request.RawUrl).GetLeftPart(UriPartial.Path); }
        }

        private void UpdateJobDetailsSection()
        {
            LabelJobTitle.Text = SPHttpUtility.NoEncode(CurrentJob.Title);
            LabelWebApplication.Text = CurrentJob.WebApplication != null
                                           ? SPHttpUtility.NoEncode(CurrentJob.WebApplication.Name)
                                           : "N/A";
            DateTime lastRunTime = CurrentJob.LastRunTime;
            LabelLastRunTime.Text =
                SPHttpUtility.HtmlEncode(
                    DateTime.Compare(lastRunTime, DateTime.MinValue) == 0
                        ? "N/A"
                        : lastRunTime.ToString(CultureInfo.CurrentCulture));
            LabelEnabled.Text = (CurrentJob.IsDisabled) ? "No" : "Yes";
            LabelSchedule.Text = CurrentJob.Schedule is SPOneTimeSchedule
                                     ? "Run one-time at " + ((SPOneTimeSchedule)CurrentJob.Schedule).Time
                                     : CurrentJob.Schedule.ToString();
        }

        protected override void OnLoad(EventArgs e)
        {
            BindControls(true);
            base.OnLoad(e);
        }

        protected override void OnLoadComplete(EventArgs e)
        {
            BindControls(false);
            if (CurrentAction == Action.ModifyJob && CurrentJob.SiteCollectionId != ChosenSiteCollectionId) Redirect();
            base.OnLoadComplete(e);
        }

        protected override void OnInit(EventArgs e)
        {
           
            if (CurrentAction != Action.ManageJobs)
            {
                ConfigureScanMode.DataSource = from JobMode jobMode in Enum.GetValues(typeof(JobMode))
                                               select new DictionaryEntry((int)jobMode, jobMode.ToFriendlyString());
                ConfigureScanMode.DataValueField = "Key";
                ConfigureScanMode.DataTextField = "Value";
                ConfigureScanMode.DataBind();

                ServersList.DataSource = from SPServer server in SPFarm.Local.Servers
                                         select new DictionaryEntry(server.Name, server.DisplayName);
                ServersList.DataValueField = "Key";
                ServersList.DataTextField = "Value";
                ServersList.DataBind();
            }
        }

        private void SetConfigList()
        {
            ConfigurationListPicker.SiteCollectionId = ChosenSiteCollectionId;
            ConfigurationListPicker.ListFilter =
                list => (int)list.BaseTemplate == GlobalConstants.ConfigurationListTemplateId;
            ConfigurationListPicker.DataBind();            
        }

        public void btnViewReport_Click(object sender, EventArgs e)
        {
            SPUtility.Redirect(SPContext.Current.Web.Url + "/" + ReportsList.SelectedValue, SPRedirectFlags.Default, HttpContext.Current);
        }

        private void BindControls(bool onPostBack)
        {
            if (onPostBack ^ IsPostBack) return; //workaround for SiteAdministrationSelector; it's ready before Load() only on postbacks

            Guid selectedSiteCollectionId = ChosenSiteCollectionId;
            if (selectedSiteCollectionId == Guid.Empty) return;

            using (SPSite selectedSite = new SPSite(selectedSiteCollectionId))
            {
                if (selectedSite.Features[GlobalConstants.SPChainGangListTemplatesFeatureId] == null)
                {
                    LabelErrorMessage.Text = "<br />SPChainGangListTemplates feature is not activated at this site collection.";//TODO: remove spaghetti code
                    LabelErrorMessage.Visible = true;
                    return;
                }

                if (CurrentAction == Action.ManageJobs)
                {
                    var jobs = from job in selectedSite.WebApplication.JobDefinitions
                               let chainGangJob = job as ChainGangJob
                               where
                                   chainGangJob != null &&
                                   chainGangJob.SiteCollectionId == selectedSiteCollectionId &&
                                   !chainGangJob.Title.StartsWith(String.Format(GlobalConstants.ImmediateRunJobNameTemplate, String.Empty))
                               select job;
                    foreach (SPJobDefinition job in jobs)
                    {
                        SPChainGangJobs.Items.Add(new ListItem(job.Title, job.Id.ToString()));
                    }
                    ReportsListHyperlink.NavigateUrl = LinkHelpers.CombineLinks(
                        selectedSite.Url, selectedSite.RootWeb.Lists[GlobalConstants.ReportsListName].DefaultViewUrl);

                    // getting the list of reports folder to sort it later
                    const string folderNamePattern = GlobalConstants.ReportFolderNamePattern;
                    var variablePartIndex = folderNamePattern.IndexOf("{0}");
                    //getting the fixed part before the first placeholder
                    var folderNamePatternFixedPart = folderNamePattern.Substring(
                        0, variablePartIndex != -1 ? variablePartIndex : folderNamePattern.Length);
                    var foldersList =
                        selectedSite.RootWeb.Lists[GlobalConstants.ReportsListName].Items.Cast
                            <SPListItem>().Where(folder => folder["URL"].ToString().Contains(folderNamePatternFixedPart)).ToList();
                    foldersList.Sort(
                        (folder1, folder2) =>
                        DateTime.Compare( //reverse chronological
                            (DateTime)folder2[SPBuiltInFieldId.Created],
                            (DateTime)folder1[SPBuiltInFieldId.Created]));

                    foreach (SPListItem folder in foldersList)
                    {
                        var folderDate = (DateTime)folder[SPBuiltInFieldId.Created];
                        var title = String.Format(
                            "{0} {1}", folderDate.ToShortDateString(), folderDate.ToLongTimeString());
                        var fieldValue = new SPFieldUrlValue(folder["URL"].ToString());
                        ReportsListBox.Items.Add(new ListItem(title, fieldValue.Url));
                    }
                }
                else
                {
                    SetConfigList();
                    CreateConfigurationListHyperlink.NavigateUrl =
                        String.Format(
                            CreateConfigurationListHyperlink.NavigateUrl, selectedSite.RootWeb.Url,
                            GlobalConstants.SPChainGangListTemplatesFeatureId,
                            GlobalConstants.ConfigurationListTemplateId);
                }
            }
        }

        void UpdateSchedule()
        {
            TypeSwitch.Do(
                CurrentJobSchedule,
                TypeSwitch.Case<SPYearlySchedule>(
                    x =>
                    {
                        TxtBeginDay.Text = x.BeginDay.ToString();
                        TxtBeginHour.Text = x.BeginHour.ToString();
                        TxtBeginMinute.Text = x.BeginMinute.ToString();
                        DDLBeginMonth.SelectedValue = x.BeginMonth.ToString();
                        TxtBeginSecond.Text = x.BeginSecond.ToString();
                        TxtEndDay.Text = x.EndDay.ToString();
                        TxtEndHour.Text = x.EndHour.ToString();
                        TxtEndMinute.Text = x.EndMinute.ToString();
                        DDLEndMonth.SelectedValue = x.EndMonth.ToString();
                        TxtEndSecond.Text = x.EndSecond.ToString();
                        RadioButtonSPYearlySchedule.Checked = true;
                    }),
                TypeSwitch.Case<SPMonthlySchedule>(
                    x =>
                    {
                        TxtBeginDay.Text = x.BeginDay.ToString();
                        TxtBeginHour.Text = x.BeginHour.ToString();
                        TxtBeginMinute.Text = x.BeginMinute.ToString();
                        TxtBeginSecond.Text = x.BeginSecond.ToString();
                        TxtEndDay.Text = x.EndDay.ToString();
                        TxtEndHour.Text = x.EndHour.ToString();
                        TxtEndMinute.Text = x.EndMinute.ToString();
                        TxtEndSecond.Text = x.EndSecond.ToString();
                        RadioButtonSPMonthlySchedule.Checked = true;
                    }),
                TypeSwitch.Case<SPWeeklySchedule>(
                    x =>
                    {
                        DDLBeginDayOfWeek.SelectedValue = x.BeginDayOfWeek.ToString();
                        TxtBeginHour.Text = x.BeginHour.ToString();
                        TxtBeginMinute.Text = x.BeginMinute.ToString();
                        TxtBeginSecond.Text = x.BeginSecond.ToString();
                        DDLEndDayOfWeek.SelectedValue = x.EndDayOfWeek.ToString();
                        TxtEndHour.Text = x.EndHour.ToString();
                        TxtEndMinute.Text = x.EndMinute.ToString();
                        TxtEndSecond.Text = x.EndSecond.ToString();
                        RadioButtonSPWeeklySchedule.Checked = true;
                    }),
                TypeSwitch.Case<SPDailySchedule>(
                    x =>
                    {
                        TxtBeginHour.Text = x.BeginHour.ToString();
                        TxtBeginMinute.Text = x.BeginMinute.ToString();
                        TxtBeginSecond.Text = x.BeginSecond.ToString();
                        TxtEndHour.Text = x.EndHour.ToString();
                        TxtEndMinute.Text = x.EndMinute.ToString();
                        TxtEndSecond.Text = x.EndSecond.ToString();
                        RadioButtonSPDailySchedule.Checked = true;
                    }),
                TypeSwitch.Case<SPHourlySchedule>(
                    x =>
                    {
                        TxtBeginMinute.Text = x.BeginMinute.ToString();
                        TxtEndMinute.Text = x.EndMinute.ToString();
                        RadioButtonSPHourlySchedule.Checked = true;
                    }),
                TypeSwitch.Case<SPMinuteSchedule>(
                    x =>
                    {
                        TxtBeginSecond.Text = x.BeginSecond.ToString();
                        TxtEndSecond.Text = x.EndSecond.ToString();
                        TxtInterval.Text = x.Interval.ToString();
                        RadioButtonSPMinutesSchedule.Checked = true;
                    }),
                TypeSwitch.Case<SPOneTimeSchedule>(
                    x =>
                    {
                        DTCTime.SelectedDate = x.Time;
                        RadioButtonSPOneTimeSchedule.Checked = true;
                    })
                );
        }

        private void UpdateJob()
        {
            CurrentJob.SiteCollectionId = ChosenSiteCollectionId;
            ConfigurationListPicker.Update();
            CurrentJob.ConfigurationListId = ConfigurationListPicker.SelectedListId;
            CurrentJob.Operation = (JobMode)Enum.Parse(typeof(JobMode), ConfigureScanMode.SelectedItem.Value);
            CurrentJob.EmailsToNotify = NotificationEmails.Text;
            //using (new Impersonation("Eugene_Borisov","PRINCETON","qwsazx`1qaz"))
            SPSecurity.RunWithElevatedPrivileges(() => CurrentJob.Update());
        }

        private void UpdateJobSchedule()
        {
            var schedule = ConstructSchedule();
            if (schedule != null)
            {
                try //TODO: move to custom validator
                {
                    SPSchedule.FromString(schedule.ToString());
                }
                catch (SPException ex)
                {
                    SPUtility.TransferToErrorPage(String.Format("Incorrect schedule was specified ({0}).", ex.Message));
                }
                CurrentJob.Schedule = schedule;
            }
        }

        protected void BtnExecute_Click(object sender, EventArgs e)
        {
            if (IsValid && ChosenSiteCollectionId != Guid.Empty)
            {
                using (var operation = new SPLongOperation(Page))
                {
                    operation.LeadingHTML = "Please wait...";
                    operation.TrailingHTML = "Setting up the job";
                    operation.Begin();
                    try
                    {
                        CreateTimerJob(String.Format(GlobalConstants.ImmediateRunJobNameTemplate, currentJob.Title), currentJob.Server);
                        currentJob.Schedule = new SPOneTimeSchedule(DateTime.Now.AddSeconds(10));
                        UpdateJob();
                    }
                    catch (Exception ex)
                    {
                        SPUtility.TransferToErrorPage(ex.Message);
                    }
                    operation.End(PageToRedirectOnCancel);
                }
                Redirect();
            }
        }

        protected void BtnDelete_Click(object sender, EventArgs e)
        {
            if (IsValid & CurrentJob != null)
            {
                CurrentJob.Delete();
                Redirect();
            }
        }

        private SPSchedule ConstructSchedule()
        {
            string scheduletype = ScheduleTypeName;
            switch (scheduletype)
            {
                case "SPYearlySchedule":
                    SPYearlySchedule schedule1 = new SPYearlySchedule();
                    schedule1.BeginDay = Convert.ToInt32(this.TxtBeginDay.Text);
                    schedule1.BeginHour = Convert.ToInt32(this.TxtBeginHour.Text);
                    schedule1.BeginMinute = Convert.ToInt32(this.TxtBeginMinute.Text);
                    schedule1.BeginMonth = Convert.ToInt32(this.DDLBeginMonth.SelectedValue);
                    schedule1.BeginSecond = Convert.ToInt32(this.TxtBeginSecond.Text);
                    schedule1.EndDay = Convert.ToInt32(this.TxtEndDay.Text);
                    schedule1.EndHour = Convert.ToInt32(this.TxtEndHour.Text);
                    schedule1.EndMinute = Convert.ToInt32(this.TxtEndMinute.Text);
                    schedule1.EndMonth = Convert.ToInt32(this.DDLEndMonth.SelectedValue);
                    schedule1.EndSecond = Convert.ToInt32(this.TxtEndSecond.Text);
                    RadioButtonSPYearlySchedule.Checked = true;
                    return schedule1;
                case "SPMonthlySchedule":
                    SPMonthlySchedule schedule2 = new SPMonthlySchedule();
                    schedule2.BeginDay = Convert.ToInt32(this.TxtBeginDay.Text);
                    schedule2.BeginHour = Convert.ToInt32(this.TxtBeginHour.Text);
                    schedule2.BeginMinute = Convert.ToInt32(this.TxtBeginMinute.Text);
                    schedule2.BeginSecond = Convert.ToInt32(this.TxtBeginSecond.Text);
                    schedule2.EndDay = Convert.ToInt32(this.TxtEndDay.Text);
                    schedule2.EndHour = Convert.ToInt32(this.TxtEndHour.Text);
                    schedule2.EndMinute = Convert.ToInt32(this.TxtEndMinute.Text);
                    schedule2.EndSecond = Convert.ToInt32(this.TxtEndSecond.Text);
                    RadioButtonSPMonthlySchedule.Checked = true;
                    return schedule2;
                case "SPWeeklySchedule":
                    SPWeeklySchedule schedule3 = new SPWeeklySchedule();
                    schedule3.BeginDayOfWeek = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), this.DDLBeginDayOfWeek.SelectedValue, true);
                    schedule3.BeginHour = Convert.ToInt32(this.TxtBeginHour.Text);
                    schedule3.BeginMinute = Convert.ToInt32(this.TxtBeginMinute.Text);
                    schedule3.BeginSecond = Convert.ToInt32(this.TxtBeginSecond.Text);
                    schedule3.EndDayOfWeek = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), this.DDLEndDayOfWeek.SelectedValue, true);
                    schedule3.EndHour = Convert.ToInt32(this.TxtEndHour.Text);
                    schedule3.EndMinute = Convert.ToInt32(this.TxtEndMinute.Text);
                    schedule3.EndSecond = Convert.ToInt32(this.TxtEndSecond.Text);
                    RadioButtonSPWeeklySchedule.Checked = true;
                    return schedule3;
                case "SPDailySchedule":
                    SPDailySchedule schedule4 = new SPDailySchedule();
                    schedule4.BeginHour = Convert.ToInt32(this.TxtBeginHour.Text);
                    schedule4.BeginMinute = Convert.ToInt32(this.TxtBeginMinute.Text);
                    schedule4.BeginSecond = Convert.ToInt32(this.TxtBeginSecond.Text);
                    schedule4.EndHour = Convert.ToInt32(this.TxtEndHour.Text);
                    schedule4.EndMinute = Convert.ToInt32(this.TxtEndMinute.Text);
                    schedule4.EndSecond = Convert.ToInt32(this.TxtEndSecond.Text);
                    RadioButtonSPDailySchedule.Checked = true;
                    return schedule4;
                case "SPHourlySchedule":
                    SPHourlySchedule schedule5 = new SPHourlySchedule();
                    schedule5.BeginMinute = Convert.ToInt32(this.TxtBeginMinute.Text);
                    schedule5.EndMinute = Convert.ToInt32(this.TxtEndMinute.Text);
                    RadioButtonSPHourlySchedule.Checked = true;
                    return schedule5;
                case "SPMinuteSchedule":
                    SPMinuteSchedule schedule6 = new SPMinuteSchedule();
                    schedule6.BeginSecond = Convert.ToInt32(this.TxtBeginSecond.Text);
                    schedule6.EndSecond = Convert.ToInt32(this.TxtEndSecond.Text);
                    schedule6.Interval = Convert.ToInt32(this.TxtInterval.Text);
                    RadioButtonSPMinutesSchedule.Checked = true;
                    return schedule6;
                case "SPOneTimeSchedule":
                    RadioButtonSPOneTimeSchedule.Checked = true;
                    return new SPOneTimeSchedule(DTCTime.SelectedDate);
                default:
                    return null;
            }
        }

        protected void BtnSaveJob_Click(object sender, EventArgs e)
        {
            if (!Page.IsValid)
                return;

            if (CurrentJob == null)
                CreateTimerJob(NewScanTitle.Text, SPFarm.Local.Servers[ServersList.SelectedValue]);

            UpdateJobSchedule();
            UpdateJob();
            Redirect();
        }

        private void Redirect()
        {
            SPUtility.Redirect(PageToRedirectOnCancel, SPRedirectFlags.Default, Context);
        }

        private void CreateTimerJob(string name, SPServer server)
        {
            using (SPSite site = new SPSite(ChosenSiteCollectionId))
            {
                SPSecurity.RunWithElevatedPrivileges(
                    () => currentJob = new ChainGangJob(name, site.WebApplication, server));
            }
        }

        private void RemoveTimerJob(Guid jobId)
        {
            using (SPSite site = new SPSite(ChosenSiteCollectionId))
            {
                site.WebApplication.JobDefinitions[jobId].Delete();
            }
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            if (LabelErrorMessage.Visible)
                return;

            if (CurrentAction != Action.ManageJobs && ScheduleTypeName != null &&
                ScheduleTypeName == CurrentScheduleTypeName)
            {
                UpdateSchedule();
            }
            if (CurrentJob != null)
            {
                UpdateJobDetailsSection();
                NotificationEmails.Text = CurrentJob.EmailsToNotify;
                ConfigurationListPicker.SelectedListId = CurrentJob.ConfigurationListId;
                ConfigureScanMode.Items.FindByValue(Convert.ToString((int)CurrentJob.Operation)).Selected = true;
                ServersList.Items.FindByValue(CurrentJob.Server.Name).Selected = true;
                ServersList.Enabled = false;
            }
            if (SPChainGangJobs.Items.Count > 0)
            {
                SPChainGangJobs.SelectedIndex = 0;
            }
            else
            {
                RemoveJob.Enabled = false;
                ModifyJob.Enabled = false;
            }
            if (ReportsListBox.Items.Count > 0)
            {
                ReportsListBox.SelectedIndex = 0;
            }
            else
            {
                ViewReportButton.Enabled = false;
            }

            SetSectionVisibility();
            SetScheduleVisibility();
        }

        void SetScheduleVisibility()
        {
            TxtBeginDay.Parent.Parent.Visible = false;
            DDLBeginDayOfWeek.Parent.Parent.Visible = false;
            TxtBeginHour.Parent.Parent.Visible = false;
            TxtBeginMinute.Parent.Parent.Visible = false;
            DDLBeginMonth.Parent.Parent.Visible = false;
            TxtBeginSecond.Parent.Parent.Visible = false;
            TxtEndDay.Parent.Parent.Visible = false;
            DDLEndDayOfWeek.Parent.Parent.Visible = false;
            TxtEndHour.Parent.Parent.Visible = false;
            TxtEndMinute.Parent.Parent.Visible = false;
            DDLEndMonth.Parent.Parent.Visible = false;
            TxtEndSecond.Parent.Parent.Visible = false;
            TxtInterval.Parent.Parent.Visible = false;
            DTCTime.Parent.Parent.Visible = false;
            RadioButtonSPOneTimeSchedule.Visible = CurrentScheduleTypeName == null;
            EmptyScheduleMessage.Visible = true;

            if (RadioButtonSPYearlySchedule.Checked)
            {
                TxtBeginDay.Parent.Parent.Visible = true;
                TxtBeginHour.Parent.Parent.Visible = true;
                TxtBeginMinute.Parent.Parent.Visible = true;
                DDLBeginMonth.Parent.Parent.Visible = true;
                TxtBeginSecond.Parent.Parent.Visible = true;
                TxtEndDay.Parent.Parent.Visible = true;
                TxtEndHour.Parent.Parent.Visible = true;
                TxtEndMinute.Parent.Parent.Visible = true;
                DDLEndMonth.Parent.Parent.Visible = true;
                TxtEndSecond.Parent.Parent.Visible = true;
                EmptyScheduleMessage.Visible = false;
            }

            if (RadioButtonSPMonthlySchedule.Checked)
            {
                TxtBeginDay.Parent.Parent.Visible = true;
                TxtBeginHour.Parent.Parent.Visible = true;
                TxtBeginMinute.Parent.Parent.Visible = true;
                TxtBeginSecond.Parent.Parent.Visible = true;
                TxtEndDay.Parent.Parent.Visible = true;
                TxtEndHour.Parent.Parent.Visible = true;
                TxtEndMinute.Parent.Parent.Visible = true;
                TxtEndSecond.Parent.Parent.Visible = true;
                EmptyScheduleMessage.Visible = false;
            }


            if (RadioButtonSPWeeklySchedule.Checked)
            {
                DDLBeginDayOfWeek.Parent.Parent.Visible = true;
                TxtBeginHour.Parent.Parent.Visible = true;
                TxtBeginMinute.Parent.Parent.Visible = true;
                TxtBeginSecond.Parent.Parent.Visible = true;
                DDLEndDayOfWeek.Parent.Parent.Visible = true;
                TxtEndHour.Parent.Parent.Visible = true;
                TxtEndMinute.Parent.Parent.Visible = true;
                TxtEndSecond.Parent.Parent.Visible = true;
                EmptyScheduleMessage.Visible = false;
            }


            if (RadioButtonSPDailySchedule.Checked)
            {
                TxtBeginHour.Parent.Parent.Visible = true;
                TxtBeginMinute.Parent.Parent.Visible = true;
                TxtBeginSecond.Parent.Parent.Visible = true;
                TxtEndHour.Parent.Parent.Visible = true;
                TxtEndMinute.Parent.Parent.Visible = true;
                TxtEndSecond.Parent.Parent.Visible = true;
                EmptyScheduleMessage.Visible = false;
            }


            if (RadioButtonSPHourlySchedule.Checked)
            {
                TxtBeginMinute.Parent.Parent.Visible = true;
                TxtEndMinute.Parent.Parent.Visible = true;
                EmptyScheduleMessage.Visible = false;
            }


            if (RadioButtonSPMinutesSchedule.Checked)
            {
                TxtBeginSecond.Parent.Parent.Visible = true;
                TxtEndSecond.Parent.Parent.Visible = true;
                TxtInterval.Parent.Parent.Visible = true;
                EmptyScheduleMessage.Visible = false;
            }


            if (RadioButtonSPOneTimeSchedule.Checked)
            {
                DTCTime.Parent.Parent.Visible = true;
                RadioButtonSPOneTimeSchedule.Visible = true;
                if (CurrentJobSchedule != null)
                {
                    SetRegularScheduleSectionVisibility(false);
                }
                EmptyScheduleMessage.Visible = false;
            }
            else
            {
                SetRegularScheduleSectionVisibility(true);
            }
        }

        private void SetRegularScheduleSectionVisibility(bool visible)
        {
            RadioButtonSPYearlySchedule.Visible = visible;
            RadioButtonSPMonthlySchedule.Visible = visible;
            RadioButtonSPWeeklySchedule.Visible = visible;
            RadioButtonSPDailySchedule.Visible = visible;
            RadioButtonSPHourlySchedule.Visible = visible;
            RadioButtonSPMinutesSchedule.Visible = visible;
            RegularSchedulePanel.Visible = visible;
        }

        private void SetSectionVisibility()
        {
            switch (CurrentAction)
            {
                case Action.AddNewJob:
                    SetNewJobSectionVisibility(true);
                    break;
                case Action.ModifyJob:
                    SetEditSectionVisibility(true);
                    break;
                default:
                    SetManageSectionVisibility(true);
                    break;
            }
        }

        public static class TypeSwitch
        {
            public delegate void Action();

            public static CaseInfo Case<T>(Action<T> action)
            {
                return new CaseInfo
                {
                    Action = x => action((T)x),
                    Target = typeof(T)
                };
            }

            public static CaseInfo Case<T>(Action action)
            {
                return new CaseInfo
                {
                    Action = x => action(),
                    Target = typeof(T)
                };
            }

            public static CaseInfo Default(Action action)
            {
                return new CaseInfo
                {
                    Action = x => action(),
                    IsDefault = true
                };
            }

            public static void Do(object source, params CaseInfo[] cases)
            {
                Type type = source.GetType();
                foreach (CaseInfo info in cases)
                {
                    if (info.IsDefault || (type == info.Target))
                    {
                        info.Action(source);
                        break;
                    }
                }
            }

            public class CaseInfo
            {
                // Properties
                public Action<object> Action { get; set; }

                public bool IsDefault { get; set; }

                public Type Target { get; set; }
            }

        }

        private void SetNewJobSectionVisibility(bool visible)
        {
            ScanTitleSection.Visible = visible;
            EmailsSection.Visible = visible;
            ConfigureScanSection.Visible = visible;
            SectionScheduleType.Visible = visible;
            SectionScheduleSettings.Visible = visible;
            ScanModeSection.Visible = visible;
            ScanServerSection.Visible = visible;
            Buttons.Visible = visible;
        }

        private void SetEditSectionVisibility(bool visible)
        {
            SetNewJobSectionVisibility(visible);
            ScanTitleSection.Visible = !visible;
            JobDetailsSection.Visible = visible;
            BtnExecute.Visible = visible;
            BtnDelete.Visible = visible;
        }

        private void SetManageSectionVisibility(bool visible)
        {
            ScheduledScansSection.Visible = visible;
            ReportsSection.Visible = visible;
        }

        private enum Action
        {
            ManageJobs,
            AddNewJob,
            ModifyJob
        }

        protected void DeleteJob(object sender, EventArgs e)
        {
            var jobToDelete = Request.Form[SPChainGangJobs.UniqueID].ConvertToGuid();
            if (jobToDelete != Guid.Empty)
            {
                RemoveTimerJob(jobToDelete);
                SPChainGangJobs.Items.Remove(SPChainGangJobs.Items.FindByValue(jobToDelete.ToString()));
            }
            //Redirect();
        }

        protected void ScheduleValidator_Validate(object source, ServerValidateEventArgs args)
        {
            try
            {
                SPSchedule schedule = ConstructSchedule();
                SPSchedule.FromString(schedule.ToString()); //exception is here if incorrect
            }
            catch (SPException e)
            {
                args.IsValid = false;
                ScheduleLogicValidator.Text = e.Message;
                ScheduleLogicValidator.Visible = true;
            }
            args.IsValid = true;
        }
    }
}